/**************************************************************************/
/*                                                                        */
/*                              WWIV Version 5.0x                         */
/*						Copyright (C)2012, Jason Whelan		              */
/*                                                                        */
/*    Licensed  under the  Apache License, Version  2.0 (the "License");  */
/*    you may not use this  file  except in compliance with the License.  */
/*    You may obtain a copy of the License at                             */
/*                                                                        */
/*                http://www.apache.org/licenses/LICENSE-2.0              */
/*                                                                        */
/*    Unless  required  by  applicable  law  or agreed to  in  writing,   */
/*    software  distributed  under  the  License  is  distributed on an   */
/*    "AS IS"  BASIS, WITHOUT  WARRANTIES  OR  CONDITIONS OF ANY  KIND,   */
/*    either  express  or implied.  See  the  License for  the specific   */
/*    language governing permissions and limitations under the License.   */
/*                                                                        */
/**************************************************************************/

/* Public Domain Curses */

#include "TextUI.h" 

  
#define _ECHAR 0x08 /* Erase char (^H) */ 
#define _BCHAR 0x7F // other backspace (^?)
#define _DWCHAR 0x17 /* Delete Word char (^W) */
#define _DLCHAR 0x15 /* Delete Line char (^U) */


//RCSID("$Id: getstrmask.cpp,v #1.51 2008/07/14 04:24:51 wmcbrine Exp $") 
/*man-start**************************************************************

  Name:                                                         getstr

  Synopsis:
        int getstrex(char *str);
        int wgetstrex(WINDOW *win, char *str);
        int mvgetstrex(int y, int x, char *str);
        int mvwgetstrex(WINDOW *win, int y, int x, char *str);
        int getnstrex(char *str, int n);
        int wgetnstrex(WINDOW *win, char *str, int n);
        int mvgetnstrex(int y, int x, char *str, int n);
        int mvwgetnstrex(WINDOW *win, int y, int x, char *str, int n);

        int get_wstrex(wint_t *wstr);
        int wget_wstrex(WINDOW *win, wint_t *wstr);
        int mvget_wstrex(int y, int x, wint_t *wstr);
        int mvwget_wstrex(WINDOW *win, int, int, wint_t *wstr);
        int getn_wstrex(wint_t *wstr, int n);
        int wgetn_wstrex(WINDOW *win, wint_t *wstr, int n);
        int mvgetn_wstrex(int y, int x, wint_t *wstr, int n);
        int mvwgetn_wstrex(WINDOW *win, int y, int x, wint_t *wstr, int n);

  Description:
        These routines call wgetch() repeatedly to build a string, 
        interpreting erase and kill characters along the way, until a 
        newline or carriage return is received. When PDCurses is built 
        with wide-character support enabled, the narrow-character 
        functions convert the wgetch()'d values into a multibyte string 
        in the current locale before returning it. The resulting string 
        is placed in the area pointed to by *str. The routines with n as 
        the last argument read at most n characters.

        Note that there's no way to know how long the buffer passed to 
        wgetstrex() is, so use wgetnstrex() to avoid buffer overflows.

  Return Value:
        This functions return ERR on failure or any other value on 
        success.

  Portability                                X/Open    BSD    SYS V
        getstr                                  Y       Y       Y
        wgetstr                                 Y       Y       Y
        mvgetstr                                Y       Y       Y
        mvwgetstr                               Y       Y       Y
        getnstr                                 Y       -      4.0
        wgetnstr                                Y       -      4.0
        mvgetnstr                               Y       -       -
        mvwgetnstr                              Y       -       -
        get_wstr                                Y
        wget_wstr                               Y
        mvget_wstr                              Y
        mvwget_wstr                             Y
        getn_wstr                               Y
        wgetn_wstr                              Y
        mvgetn_wstr                             Y
        mvwgetn_wstr                            Y

**man-end****************************************************************/

#define MAXLINE 255

int wgetnstrex(WINDOW *win, char *str, int n, char mask = NULL)
{
#ifdef PDC_WIDE
    wchar_t wstr[MAXLINE + 1];

    if (n < 0 || n > MAXLINE)
        n = MAXLINE;

    if (wgetn_wstrex(win, (wint_t *)wstr, n) == ERR)
        return ERR;

    return PDC_wcstombs(str, wstr, n);
#else
    int ch, i, num, x, chars;
    char *p;
    bool stop, oldecho, oldcbreak, oldnodelay;

    //PDC_LOG(("wgetnstrex() - called\n"));

    if (!win || !str)
        return ERR;

    chars = 0;
    p = str;
    stop = FALSE;

//    x = win->_curx;

//    oldcbreak = SP->cbreak; /* remember states */
//    oldecho = SP->echo;
//    oldnodelay = win->_nodelay;

//    SP->echo = FALSE;       /* we do echo ourselves */
    noecho();
    oldecho=TRUE;
    cbreak();               /* ensure each key is returned immediately */
//    win->_nodelay = FALSE;  /* don't return -1 */

    wrefresh(win);

    while (!stop)
    {
        ch = wgetch(win);

        switch (ch)
        {

        case '\t':
            ch = ' ';
            num = TABSIZE - (win->_curx - x) % TABSIZE;
            for (i = 0; i < num; i++)
            {
                if (chars < n)
                {
                    if (oldecho) 
                        waddch(win, ch);
                    *p++ = ch;
                    ++chars;
                }
                else
                    beep();
            }
            break;

        case _ECHAR:        /* CTRL-H -- Delete character */
        case _BCHAR:
            if (p > str)
            {
                if (oldecho) 
                    waddstr(win, "\b \b");
                ch = (unsigned char)(*--p);
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
                chars--;
            }
            break;

        case _DLCHAR:       /* CTRL-U -- Delete line */
            while (p > str)
            {
                if (oldecho) 
                    waddstr(win, "\b \b");
                ch = (unsigned char)(*--p);
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
            }
            chars = 0;
            break;

        case _DWCHAR:       /* CTRL-W -- Delete word */

            while ((p > str) && (*(p - 1) == ' '))
            {
                if (oldecho) 
                    waddstr(win, "\b \b");

                --p;        /* remove space */
                chars--;
            }
            while ((p > str) && (*(p - 1) != ' '))
            {
                if (oldecho) 
                    waddstr(win, "\b \b");

                ch = (unsigned char)(*--p);
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
                chars--;
            }
            break;

        case '\n':
        case '\r':
            stop = TRUE;
            if (oldecho) 
                waddch(win, '\n');
            break;

		case 0x1b:  //escaped out
			return ERR;
			break;

        default:
            if (chars < n)
            {
                if (/*!SP->key_code &&*/ ch < 0x100)
                {
                    *p++ = ch;
                    if (oldecho) 
						if (mask)
							waddch(win, mask);  // mask the output
						else
							waddch(win, ch);
                    chars++;
                }
            }
            else
                beep();

            break;
      
        }

        wrefresh(win);
    }

    *p = '\0';

//    SP->echo = oldecho;     /* restore old settings */
//    SP->cbreak = oldcbreak;
//    win->_nodelay = oldnodelay;

    return OK;
#endif
}

int getstrex(char *str, char mask = NULL)
{
    //PDC_LOG(("getstrex() - called\n"));

    return wgetnstrex(stdscr, str, MAXLINE, mask);
}

int wgetstrex(WINDOW *win, char *str, char mask = NULL)
{
    //PDC_LOG(("wgetstrex() - called\n"));

    return wgetnstrex(win, str, MAXLINE, mask);
}

int mvgetstrex(int y, int x, char *str, char mask = NULL)
{
    //PDC_LOG(("mvgetstrex() - called\n"));

    if (move(y, x) == ERR)
        return ERR;

    return wgetnstrex(stdscr, str, MAXLINE, mask);
}

int mvwgetstrex(WINDOW *win, int y, int x, char *str, char mask = NULL)
{
    //PDC_LOG(("mvwgetstrex() - called\n"));

    if (wmove(win, y, x) == ERR)
        return ERR;

    return wgetnstrex(win, str, MAXLINE, mask);
}

int getnstrex(char *str, int n, char mask = NULL)
{
    //PDC_LOG(("getnstrex() - called\n"));

    return wgetnstrex(stdscr, str, n, mask);
}

int mvgetnstrex(int y, int x, char *str, int n, char mask = NULL)
{
    //PDC_LOG(("mvgetnstrex() - called\n"));

    if (move(y, x) == ERR)
        return ERR;

    return wgetnstrex(stdscr, str, n, mask);
}

int mvwgetnstrex(WINDOW *win, int y, int x, char *str, int n, char mask = NULL)
{
    //PDC_LOG(("mvwgetnstrex() - called\n"));

    if (wmove(win, y, x) == ERR)
        return ERR;

    return wgetnstrex(win, str, n, mask);
}

#ifdef PDC_WIDE
int wgetn_wstrex(WINDOW *win, wint_t *wstr, int n, char mask = NULL)
{
    int ch, i, num, x, chars;
    wint_t *p;
    bool stop, oldecho, oldcbreak, oldnodelay;

    //PDC_LOG(("wgetn_wstrex() - called\n"));

    if (!win || !wstr)
        return ERR;

    chars = 0;
    p = wstr;
    stop = FALSE;

//    x = win->_curx;

//    oldcbreak = SP->cbreak; /* remember states */
//    oldecho = SP->echo;
//    oldnodelay = win->_nodelay;

//    SP->echo = FALSE;       /* we do echo ourselves */
    noecho();
    oldecho=TRUE;
    cbreak();               /* ensure each key is returned immediately */
//    win->_nodelay = FALSE;  /* don't return -1 */

    wrefresh(win);

    while (!stop)
    {
        ch = wgetch(win);

        switch (ch)
        {

        case '\t':
            ch = ' ';
            num = TABSIZE - (win->_curx - x) % TABSIZE;
            for (i = 0; i < num; i++)
            {
                if (chars < n)
                {
                    if (oldecho) 
                        waddch(win, ch);
                    *p++ = ch;
                    ++chars;
                }
                else
                    beep();
            }
            break;

        case _ECHAR:        /* CTRL-H -- Delete character */
        case _BCHAR:
            if (p > wstr)
            {
                if (oldecho) 
                    waddstr(win, "\b \b");
                ch = *--p;
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
                chars--;
            }
            break;

        case _DLCHAR:       /* CTRL-U -- Delete line */
            while (p > wstr)
            {
                if (oldecho) 
                    waddstr(win, "\b \b");
                ch = *--p;
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
            }
            chars = 0;
            break;

        case _DWCHAR:       /* CTRL-W -- Delete word */

            while ((p > wstr) && (*(p - 1) == ' '))
            {
                if (oldecho) 
                    waddstr(win, "\b \b");

                --p;        /* remove space */
                chars--;
            }
            while ((p > wstr) && (*(p - 1) != ' '))
            {
                if (oldecho) 
                    waddstr(win, "\b \b");

                ch = *--p;
                if ((ch < ' ') && (oldecho))
                    waddstr(win, "\b \b");
                chars--;
            }
            break;

        case '\n':
        case '\r':
            stop = TRUE;
            if (oldecho) 
                waddch(win, '\n');
            break;

        default:
            if (chars < n)
            {
//                if (!SP->key_code)
//                {
                    *p++ = ch;
                    if (oldecho)
						if (mask)
							waddch(win, mask);  // mask the output
						else
							waddch(win, ch);
                    chars++;
//                }
            }
            else
                beep();

            break;
      
        }

        wrefresh(win);
    }

    *p = '\0';

//    SP->echo = oldecho;     /* restore old settings */
//    SP->cbreak = oldcbreak;
//    win->_nodelay = oldnodelay;

    return OK;
}

int get_wstrex(wint_t *wstr, char mask = NULL)
{
    //PDC_LOG(("get_wstrex() - called\n"));

    return wgetn_wstrex(stdscr, wstr, MAXLINE, mask);
}

int wget_wstrex(WINDOW *win, wint_t *wstr, char mask = NULL)
{
    //PDC_LOG(("wget_wstrex() - called\n"));

    return wgetn_wstrex(win, wstr, MAXLINE, mask);
}

int mvget_wstrex(int y, int x, wint_t *wstr, char mask = NULL)
{
    //PDC_LOG(("mvget_wstrex() - called\n"));

    if (move(y, x) == ERR)
        return ERR;

    return wgetn_wstrex(stdscr, wstr, MAXLINE, mask);
}

int mvwget_wstrex(WINDOW *win, int y, int x, wint_t *wstr, char mask = NULL)
{
    //PDC_LOG(("mvwget_wstrex() - called\n"));

    if (wmove(win, y, x) == ERR)
        return ERR;

    return wgetn_wstrex(win, wstr, MAXLINE, mask);
}

int getn_wstrex(wint_t *wstr, int n, char mask = NULL)
{
    //PDC_LOG(("getn_wstrex() - called\n"));

    return wgetn_wstrex(stdscr, wstr, n, mask);
}

int mvgetn_wstrex(int y, int x, wint_t *wstr, int n, char mask = NULL)
{
    //PDC_LOG(("mvgetn_wstrex() - called\n"));

    if (move(y, x) == ERR)
        return ERR;

    return wgetn_wstrex(stdscr, wstr, n, mask);
}

int mvwgetn_wstrex(WINDOW *win, int y, int x, wint_t *wstr, int n, char mask = NULL)
{
    //PDC_LOG(("mvwgetn_wstrex() - called\n"));

    if (wmove(win, y, x) == ERR)
        return ERR;

    return wgetn_wstrex(win, wstr, n, mask);
}
#endif
